package com.personal.dataconvert.util;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Element;

import com.personal.core.bean.CountEntity;
import com.personal.core.utils.Assert;
import com.personal.core.utils.CoreUtil;
import com.personal.core.xml.XMLDoc;
import com.personal.dataconvert.bean.HeaderConfig;
import com.personal.dataconvert.bean.SheetConfig;
import com.personal.dataconvert.bean.StyleConfig;
import com.personal.dataconvert.bean.WorkBookConfig;

/**
 * 配置App
 * @author cuibo
 *
 */
public class ExportExcelConfigApp
{

    private static Map<String, WorkBookConfig> configMap = new HashMap<String, WorkBookConfig>();

    private static final Object LOCK = new Object();
    
    /**
     * 注入导出配置流
     * @param in
     * @throws Exception 
     */
    public static void setConfigStream(InputStream in) throws Exception
    {
        if (in == null)
        {
            return;
        }
        synchronized (ExportExcelConfigApp.LOCK)
        {
            Map<String, WorkBookConfig> configMap = ExportExcelConfigApp.load(in);
            if (configMap != null && !configMap.isEmpty())
            {
                ExportExcelConfigApp.configMap.putAll(configMap);
            }
        }
    }

    /**
     * 通过配置ID获取WorkBookConfig
     * @param configId
     * @return
     * @throws Exception 
     */
    public static WorkBookConfig getWorkBookConfig(String configId) throws Exception
    {
        if (configMap == null)
        {
            throw new Exception("注入的导出配置文件信息为空！");
        }
        return CoreUtil.deepCopy(ExportExcelConfigApp.configMap.get(configId));
    }

    private static Map<String, WorkBookConfig> load(InputStream in) throws Exception
    {
        try
        {
            Map<String, WorkBookConfig> result = new HashMap<String, WorkBookConfig>();
            XMLDoc doc = new XMLDoc();
            doc.load(in);
            Element root = doc.getRootElement();
            Assert.isNotNull(root, "获取根节点失败！");
            List<Element> books = doc.getChildList(root);
            WorkBookConfig bookConfig = null;
            for (Element bookElement : books)
            {
                bookConfig = ExportExcelConfigApp.parseBookElement(bookElement, doc);
                if (bookConfig != null)
                {
                    result.put(bookConfig.getId(), bookConfig);
                }
            }
            return result;
        } finally
        {
            ExcelHtmlUtil.release(in);
        }
    }

    private static WorkBookConfig parseBookElement(Element bookElement, XMLDoc doc) throws Exception
    {
        String bookId = bookElement.getAttribute("id");
        Assert.isNotNullOrEmpty(bookId, "Excel导出配置中，存在配置ID为空的配置！");
        List<Element> sheetElements = doc.getChildList(bookElement);
        if (sheetElements == null || sheetElements.isEmpty())
        {
            return null;
        }
        WorkBookConfig bookConfig = new WorkBookConfig();
        bookConfig.setId(bookId);
        for (Element sheetElement : sheetElements)
        {
            if ("styleConfig".equals(sheetElement.getTagName()))
            {
                ExportExcelConfigApp.parseConfigElement(sheetElement, doc, bookConfig);
            } else if ("sheet".equals(sheetElement.getTagName()))
            {
                ExportExcelConfigApp.parseSheetElement(sheetElement, doc, bookConfig);
            }
        }
        return bookConfig;
    }

    /**
     * 解析样式
     * @param sheetElement
     * @param doc
     * @param bookConfig
     */
    private static void parseConfigElement(Element configElement, XMLDoc doc, WorkBookConfig bookConfig)
    {
        StyleConfig config = new StyleConfig();
        config.setTitleFont(configElement.getAttribute("titleFont"));
        if (!CoreUtil.isEmpty(configElement.getAttribute("titleFontSize")))
        {
            config.setTitleFontSize(CoreUtil.parseInt(configElement.getAttribute("titleFontSize")));
        }
        if (!CoreUtil.isEmpty(configElement.getAttribute("titleHeight")))
        {
            config.setTitleHeight(CoreUtil.parseInt(configElement.getAttribute("titleHeight")));
        }
        config.setHeaderFont(configElement.getAttribute("headerFont"));
        if (!CoreUtil.isEmpty(configElement.getAttribute("headerFontSize")))
        {
            config.setHeaderFontSize(CoreUtil.parseInt(configElement.getAttribute("headerFontSize")));
        }
        if (!CoreUtil.isEmpty(configElement.getAttribute("headerHeight")))
        {
            config.setHeaderHeight(CoreUtil.parseInt(configElement.getAttribute("headerHeight")));
        }
        config.setBodyFont(configElement.getAttribute("bodyFont"));
        if (!CoreUtil.isEmpty(configElement.getAttribute("bodyFontSize")))
        {
            config.setBodyFontSize(CoreUtil.parseInt(configElement.getAttribute("bodyFontSize")));
        }
        if (!CoreUtil.isEmpty(configElement.getAttribute("bodyHeight")))
        {
            config.setBodyHeight(CoreUtil.parseInt(configElement.getAttribute("bodyHeight")));
        }
        config.setTitleBold(!"false".equalsIgnoreCase(configElement.getAttribute("titleBold")));
        config.setHeaderBold("true".equalsIgnoreCase(configElement.getAttribute("headerBold")));
        bookConfig.setStyleConfig(config);
    }

    /**
     * 递归子集
     * @param headerElement
     * @param sheetConfig
     * @param parentConfig
     * @param doc
     * @param countEntity
     */
    private static void parseHeaderElement(Element headerElement, SheetConfig sheetConfig, HeaderConfig parentConfig,
            XMLDoc doc, CountEntity countEntity)
    {
        // 深度 + 1
        countEntity.add();
        // 设置SheetConfig的最大深度
        if (countEntity.getCount() > sheetConfig.getMaxDeepLength())
        {
            sheetConfig.setMaxDeepLength(countEntity.getCount());
        }
        HeaderConfig headerConfig = new HeaderConfig();
        headerConfig.setSheetConfig(sheetConfig);
        headerConfig.setDeepLength(countEntity.getCount());
        headerConfig.fillInfo(headerElement);
        headerConfig.setParent(parentConfig);
        parentConfig.getChildren().add(headerConfig);

        // 如果仍存在子节点,则递归
        List<Element> childs = doc.getChildList(headerElement);
        if (childs != null && childs.size() > 0)
        {
            CountEntity childCountEntity = new CountEntity();
            for (Element element : childs)
            {
                childCountEntity.setCount(countEntity.getCount());
                ExportExcelConfigApp.parseHeaderElement(element, sheetConfig, headerConfig, doc, childCountEntity);
            }
        }
    }

    /**
     * 解析Header节点
     * @param headerElement
     * @param sheetConfig
     * @param doc
     */
    private static void parseHeaderElement(Element headerElement, SheetConfig sheetConfig,
            List<HeaderConfig> headerConfigs, XMLDoc doc)
    {
        HeaderConfig headerConfig = new HeaderConfig();
        headerConfig.setSheetConfig(sheetConfig);
        headerConfig.setDeepLength(1);
        headerConfig.fillInfo(headerElement);
        headerConfigs.add(headerConfig);

        // 如果仍存在子节点
        List<Element> childs = doc.getChildList(headerElement);
        if (childs != null && childs.size() > 0)
        {
            for (Element element : childs)
            {
                ExportExcelConfigApp.parseHeaderElement(element, sheetConfig, headerConfig, doc, new CountEntity(1));
            }
        }
    }

    private static void parseSheetElement(Element sheetElement, XMLDoc doc, WorkBookConfig bookConfig) throws Exception
    {
        SheetConfig sheetConfig = new SheetConfig();
        sheetConfig.setBookConfig(bookConfig);
        sheetConfig.setLeftHeader(sheetElement.getAttribute("leftHeader"));
        sheetConfig.setRightHeader(sheetElement.getAttribute("rightHeader"));
        sheetConfig.setTitle(sheetElement.getAttribute("title"));
        sheetConfig.setName(sheetElement.getAttribute("name"));
        if (!CoreUtil.isEmpty(sheetElement.getAttribute("index")))
        {
            sheetConfig.setIndex(CoreUtil.parseInt(sheetElement.getAttribute("index")));
        }
        if (!CoreUtil.isEmpty(sheetElement.getAttribute("titleRowCount")))
        {
            sheetConfig.setTitleRowCount(CoreUtil.parseInt(sheetElement.getAttribute("titleRowCount")));
        }
        Assert.isNotNullOrEmpty(sheetConfig.getName(), bookConfig.getId() + "下Sheet页名称不能为空！");
        bookConfig.getSheetConfigs().add(sheetConfig);
        List<Element> headerElements = doc.getChildList(sheetElement);
        if (headerElements == null || headerElements.isEmpty())
        {
            return;
        }
        List<HeaderConfig> headerConfigs = new ArrayList<HeaderConfig>();
        for (Element headerElement : headerElements)
        {
            ExportExcelConfigApp.parseHeaderElement(headerElement, sheetConfig, headerConfigs, doc);
        }
        sheetConfig.setHeaderConfigs(headerConfigs);
    }
}
